home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 34
/
Amiga Format CD34 (1998-11-20)(Future Publishing)(GB)[!][Christmas issue].iso
/
-seriously_amiga-
/
emulation
/
afid
/
afid.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-10-20
|
38KB
|
1,450 lines
/*
* afid -- like the Apple ][ program called FID, a file handling utility
*
* version 1.1
*
* We operate on files which contain entire Apple ][ diskettes from
* track 0, sector 0 to track 34, sector 15. To keep things simple,
* the entire disk image is slurped into memory. I assume the standard
* disk geometry of 35 tracks and 16 sectors when initializing, but
* otherwise the code should operate on different geometries. Different
* geometries are a chicken and egg problem as the geometry info is
* defined to be on track 0x11, sector 0, but you need the sector size
* to figure out where track 0x11 is! I have tried to make reasonable
* extrapolations to account for different geometry sizes (e.g., put
* as many directory entries per sector as possible).
*
* Since I'll want to run this on an MS-DOS machine, I am careful to
* allocate memory in small chunks, use an ANSI C compiler and use
* longs when the numbers will get bigger than 16 bits (i.e., the
* number of bytes per disk).
*
*
* Author: version 1.0.
* George Phillips <phillips@cs.ubc.ca>
* Department of Computer Science
* University of British Columbia
*
* New for version 1.1.
*
* 1) Added a help message listing the commands.
* 2) Added the ability to load different file images from within afid,
* so you no longer need to exit and enter with a new image.
* 3) Prompts the user when attempting to exit without saving a changed
* disk image.
* 4) Added new commands like load, type, lock, unlock, rename, delete, list
*
* Author: version 1.1.
* Peter Nyhlen <pnyhlen@usa.net>
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
/* This stuff really belongs in a header file */
/******************* afid.h *******************/
struct track
{
unsigned char** sector;
};
struct disk
{
int bytes_per_sector;
int sectors_per_track;
int tracks_per_disk;
struct track* track;
};
struct afile
{
int filetype;
struct disk* d;
int ts_s, ts_t, ts_ent, dt_t, dt_s, dt_pos;
int eof, secgroup, dir_t, dir_s, dir_off;
};
/* handy disk address macros for getting at particular bytes and words */
#define byteat(d, t, s, n) ((d)->track[(t)].sector[(s)][(n)])
#define wordat(d, t, s, n) (byteat(d, t, s, n) + byteat(d, t, s, (n) + 1) * 256)
/* logical constants */
#define DELETE 'D'
#define UNDELETE 'U'
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/*************** end of afid.h ****************/
/* Function Prototypes */
void build_disk_mem(struct disk*);
void load_disk(struct disk* d, char*);
void read_disk(struct disk*, FILE*);
void verify_geometry(struct disk*);
void list_help_msg();
int confirm_changes(int);
void catalog(struct disk*);
int apptoascii(int), asciitoapp(int);
void* alloc(int);
void show_freemap(struct disk*);
int isfree(struct disk*, int, int);
int allocate_sector(struct disk*, int*, int*, int);
void alloc_sector(struct disk*, int, int);
void free_sector(struct disk*, int, int);
void zero_sector(struct disk*, int, int);
int aopen(struct disk*, char*, struct afile*, char*);
int aclose(struct afile*);
int agetc(struct afile*);
int aputc(struct afile*, int);
long agetw(struct afile*);
int isfilename(char*, struct disk*, int, int, int);
void aputfilename(char*, struct disk*, int, int, int);
int tokenize(char* , char** );
void hexdump(FILE*, struct afile*);
int traverse_tsl(struct afile* af, int operation);
int dtraverse_tsl(struct afile* af, int operation);
int utraverse_tsl(struct afile* af, int operation);
main(int argc, char* argv[])
{
struct disk d;
struct afile af;
int textmode = 0;
int disk_image_loaded = TRUE;
int any_unsaved_changes = FALSE;
/* Initialize Disk Structure */
d.bytes_per_sector = 256;
d.sectors_per_track = 16;
d.tracks_per_disk = 35;
build_disk_mem(&d);
/* Process Arguments */
switch (argc)
{
case 1:
disk_image_loaded = FALSE;
list_help_msg();
break;
case 2:
load_disk(&d, argv[1]);
break;
default:
fprintf(stderr, "usage: afid disk-image-file\n");
exit(1);
}
/* Loop Through Interactive Command Processing */
for (;;)
{
char buf[1024], *arg[10], *p, *cmd;
/* Command Line Prompt */
printf("] ");
fflush(stdout);
/* Get User Input */
if (!fgets(buf, 1024, stdin))
break;
/* Parse Command Line */
tokenize(buf, arg);
cmd = arg[0];
if (!*cmd)
continue;
/* Process Command */
if (!strcmp(cmd, "load"))
{
if (confirm_changes(any_unsaved_changes))
{
load_disk(&d, arg[1]);
disk_image_loaded = TRUE;
}
}
else if (!strcmp(cmd, "help"))
list_help_msg();
else if (!strcmp(cmd, "quit") || !strcmp(cmd, "exit"))
{
if (confirm_changes(any_unsaved_changes))
break;
}
else if (!disk_image_loaded)
fprintf(stderr, "no disk image loaded.\nunable to execute %s\n", cmd);
else if (!strcmp(cmd, "catalog"))
catalog(&d);
else if (!strcmp(cmd, "free"))
show_freemap(&d);
else if (!strcmp(cmd, "text"))
textmode = 1;
else if (!strcmp(cmd, "binary"))
textmode = 0;
else if (!strcmp(cmd, "mode"))
switch (textmode) /* display transfere mode */
{
case 0:
printf("binary\n");
break;
case 1:
printf("text\n");
break;
default:
fprintf(stderr, "corrupted file type.\n");
exit(2);
}
else if (!strcmp(cmd, "type"))
{
int filetype;
/* check file type specified */
switch (toupper(arg[2][0]))
{
case 'T': filetype = 0; break;
case 'I': filetype = 1; break;
case 'A': filetype = 2; break;
case 'B': filetype = 4; break;
case 'S': filetype = 8; break;
case 'R': filetype = 16; break;
default : filetype = -1; break;
}
/* define file type */
if (filetype<0)
fprintf(stderr, "filetype %s is invalid.\n", arg[2]);
else if (!aopen(&d, arg[1], &af, textmode ? "rt" : "rb"))
fprintf(stderr, "couldn't open ][ file %s\n", arg[1]);
else
{
/* check for locked file */
if (byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) & 0x80)
fprintf(stderr, "%s is locked.\n", arg[1]);
else /* find file and change type */
{
byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) = filetype;
any_unsaved_changes = TRUE;
}
if (aclose(&af) == EOF)
fprintf(stderr, "error on closing ][ file %s\n", arg[1]);
}
}
else if (!strcmp(cmd, "reorder"))
{
int t, s;
void* temp;
for (t = 0; t < d.tracks_per_disk; t++)
{
for (s = 1; s < d.sectors_per_track / 2; s++)
{
temp = d.track[t].sector[s];
d.track[t].sector[s] =
d.track[t].sector[d.sectors_per_track - s - 1];
d.track[t].sector[d.sectors_per_track - s - 1] = temp;
}
}
any_unsaved_changes = TRUE;
}
else if (!strcmp(cmd, "lock") || !strcmp(cmd, "unlock"))
{
/* find file and lock/unlock it */
if (!aopen(&d, arg[1], &af, textmode ? "rt" : "rb"))
fprintf(stderr, "couldn't find ][ file %s\n", arg[1]);
else
{
if (!strcmp(cmd, "lock"))
byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) |= 0x80;
else
byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) &= 0x7F;
any_unsaved_changes = TRUE;
}
if (aclose(&af) == EOF)
fprintf(stderr, "error on closing ][ file %s\n", arg[1]);
}
else if (!strcmp(cmd, "rename"))
{
/* check for existing file name */
if (aopen(&d, arg[2], &af, textmode ? "rt" : "rb"))
{
fprintf(stderr, "couldn't rename file %s\n", arg[2]);
fprintf(stderr, "%s already exists!\n", arg[2]);
if (aclose(&af) == EOF)
fprintf(stderr, "error on closing ][ file %s\n", arg[2]);
}
else if (!aopen(&d, arg[1], &af, textmode ? "rt" : "rb"))
fprintf(stderr, "couldn't open ][ file %s\n", arg[1]);
else
{
/* check for locked file */
if (byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) & 0x80)
fprintf(stderr, "%s is locked.\n", arg[1]);
else /* rename file */
{
aputfilename(arg[2], af.d, af.dir_t, af.dir_s, af.dir_off);
any_unsaved_changes = TRUE;
}
if (aclose(&af) == EOF)
fprintf(stderr, "error on closing ][ file %s\n", arg[1]);
}
}
else if (!strcm